pub mod errors;
pub mod response;
pub mod jwt;

use std::env::{var, VarError};
use serde::Deserialize;
use sqlx::{Error, PgPool};
use sqlx::postgres::PgPoolOptions;

/// 应用程序核心配置结构体
/// 用于从环境变量中反序列化配置参数
/// 需配合 serde 的 Deserialize 特性使用
#[derive(Debug, Clone, Deserialize)]
pub struct Config {
    /// 服务监听的主机地址
    /// 常见取值：
    /// - "0.0.0.0"：允许所有网络接口访问（生产环境常用）
    /// - "127.0.0.1"：仅允许本地访问（开发环境常用）
    pub host: String,

    /// 服务监听的端口号
    /// 取值范围：1-65535（1-1024 为特权端口，非root用户可能无法使用）
    /// 常见取值：8080、8000、3000 等
    pub port: u16,

    /// 数据库连接字符串
    /// 格式依数据库类型而定，例如：
    /// - PostgreSQL: "postgres://user:password@localhost:5432/db_name?sslmode=disable"
    /// - MySQL: "mysql://user:password@localhost:3306/db_name"
    /// 需包含用户名、密码、主机、端口和数据库名
    pub database_url: String,

    /// Redis 服务器连接地址
    /// 格式："redis://[:password]@host:port/db"
    /// 示例："redis://user:pass@localhost:6379/0"（db为数据库编号，默认为0）
    pub redis_url: String,

    /// JWT 签名密钥
    /// 用于生成和验证 JWT 令牌的密钥，建议：
    /// - 长度至少 32 字节（增强安全性）
    /// - 生产环境中通过环境变量注入，避免硬编码
    /// - 定期轮换以降低泄露风险
    pub jwt_secret: String,

    /// JWT 令牌过期时间（单位：分钟）
    /// 需根据业务场景设置，例如：
    /// - 短期访问令牌：15-30 分钟
    /// - 长期刷新令牌：7-30 天（需配合刷新机制）
    pub jwt_expiration: i64,
}

pub type DbPool = PgPool;

impl Config {
    /// 从环境变量加载配置并构建 Config 实例
    /// 逻辑说明：
    /// - 必需配置项（如数据库地址、JWT密钥）缺失时会直接 panic（生产环境可改为返回 Result）
    /// - 可选配置项（如主机、端口）缺失时使用默认值
    /// - 数值类型配置（如端口、过期时间）会尝试从字符串解析，失败时使用默认值
    /// 返回值：成功时返回 Config 实例，环境变量读取失败时返回 VarError
    pub fn from_env() -> Result<Self, VarError> {
        Ok(Config {
            host: var("HOST").unwrap_or_else(|_| "127.0.0.1".to_string()),
            port: var("PORT").unwrap_or_else(|_| "8080".to_string()).parse().unwrap_or(8080),
            database_url: var("DATABASE_URL").expect("数据库地址不能为空！"),
            redis_url: var("REDIS_URL").expect("Redis数据库地址不能为空！"),
            jwt_secret: var("JWT_SECRET").expect("TOKEN密钥不能为空！"),
            // 24小时
            jwt_expiration: var("JWT_EXPIRATION").unwrap_or_else(|_| "8640".to_string()).parse().unwrap_or(8640),
        })
    }

    /// 创建数据库连接池
    ///
    /// # 参数
    /// * `database_url` - 数据库连接字符串
    ///
    /// # 返回
    /// 返回一个异步结果，包含数据库连接池或者sqlx错误
    pub async fn create_db_pool(&self) -> Result<DbPool, Error> {
        PgPoolOptions::new()
            .max_connections(5)
            .connect(&self.database_url)
            .await
    }
}